package hyl.core.reflect;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.objenesis.strategy.StdInstantiatorStrategy;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.BeanSerializer;

import hyl.core.io.MyFile;

/**
 * 批量序列化反序列化工具类
 * 
 * 这里封装的kryo 引擎 比较过后发现目前它是最快的序列化引擎(对比 fst jdk自带)
 * 
 * 适用于不复杂的对象, 并且需要快速序列化的场合
 * 
 * @author 阿友 3798955@qq.com
 *
 */
public class MyKryo {
	Kryo _kryo = null;
//	static MyKryo _mk;
	private static final ThreadLocal<MyKryo> kryoLocal = new ThreadLocal<MyKryo>() {
		@Override
		protected MyKryo initialValue() {
			Kryo kryo = new Kryo();
			/**
			 * <br>
			 * 不要轻易改变这里的配置！更改之后，序列化的格式就会发生变化，<br>
			 * <br>
			 * 否则那些缓存再回来反序列化的时候，就会报错<br>
			 */
//支持对象循环引用（否则会栈溢出）
			kryo.setReferences(true);
			// 默认值就是 true，添加此行的目的是为了提醒维护者，不要改变这个配置

//不强制要求注册类（注册行为无法保证多个 JVM 内同一个类的注册编号相同；而且业务系统中大量的 Class 也难以一一注册）
			kryo.setRegistrationRequired(false);
//默认值就是 false，添加此行的目的是为了提醒维护者，不要改变这个配置
			kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
			MyKryo mk = new MyKryo();
			mk._kryo = kryo;
			return mk;
		}
	};

	public static MyKryo getLocal() {

		return kryoLocal.get();
	}

	/**
	 * 实例化新的引擎
	 * 
	 * @param clazz
	 * @return
	 */
	public static MyKryo getInstance(Class<?> clazz) {
		MyKryo mk = new MyKryo();
		mk._kryo = new Kryo();
		mk._kryo.setReferences(false);
		mk._kryo.setRegistrationRequired(false);
		// _mk.kryo.register(clazz);
		mk._kryo.register(clazz, new BeanSerializer<>(mk._kryo, clazz));
		mk._kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
		return mk;
	}

	public static MyKryo getInstance() {
		MyKryo mk = new MyKryo();
		mk._kryo = new Kryo();
		mk._kryo.setReferences(false);
		mk._kryo.setRegistrationRequired(false);
		mk._kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
		return mk;
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 * @param obj
	 * @return
	 */
	public byte[] serialize(Object obj) {
		if (obj == null)
			return null;
		byte[] buffer = new byte[2048];
		try (Output output = new Output(buffer);) {
			_kryo.writeClassAndObject(output, obj);
			byte[] bytes = output.toBytes();
			output.flush();
			output.close();
			return bytes;
		} catch (Exception e) {
			return null;
		}
	
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 */
	public byte[] serialize(Object obj, File file) {
		if (file == null || obj == null)
			return null;
		byte[] bytes = serialize(obj);
		MyFile.writeBytes(file, bytes);
		return bytes;
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 */
	public byte[] serialize(Object obj, OutputStream file) {
		if (file == null || obj == null)
			return null;
		byte[] bytes = serialize(obj);
		MyFile.appendBytes(file, bytes);
		try {
			file.close();
			return bytes;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 */
	@SuppressWarnings({ "unchecked", "resource" })
	public <T> T deserialize(byte[] bytes) {
		if (bytes == null)
			return null;
		Input input = new Input(bytes);
		try {
			return (T) _kryo.readClassAndObject(input);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 */
	@SuppressWarnings("unchecked")
	public <T> T deserialize(InputStream file) {
		if (file == null)
			return null;
		Input input = new Input(file, 2048);

		return (T) _kryo.readClassAndObject(input);
	}

	/**
	 * 不要用于大对象 ,要用于小对象
	 * 
	 */
	public <T> T deserialize(File file) {
		if (file == null)
			return null;
//		byte[] bytes;
//		try {
//			bytes = MyFile.readAllBytes(file);
//		} catch (Exception e) {
//			return null;
//		}
//		if (bytes == null)
//			return nu

		try {
			return deserialize(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

}
